/**
 *
 */
// 涉及的表名
const dbName = require("../config.js");

var dao = {};
var util = {};
// 初始化
dao.init = function(obj) {
	util = obj;
}
/**
 * 查 - 根据id获取单条记录
 * @params {String} _id
 * @params {Object} fieldJson 字段显示规则
 * 调用示例
 * let orderInfo = await vk.daoCenter.orderDao.findById(_id);
 */
dao.findById = async (_id, fieldJson) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.findById({
		dbName: dbName.order,
		id: _id,
		fieldJson
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};
/**
 * 查 - 根据order_no获取单条记录
 * 调用示例
let orderInfo = await vk.daoCenter.orderDao.findByOrderNo(order_no);
 */
dao.findByOrderNo = async (order_no = "___", fieldJson) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.findByWhereJson({
		dbName: dbName.order,
		whereJson: {
			order_no
		},
		fieldJson
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 根据whereJson获取单条记录
 * @params {Object} whereJson 条件
 * @params {Object} fieldJson 字段显示规则
 * 调用示例
let orderInfo = await vk.daoCenter.orderDao.findByWhereJson({

});
 */
dao.findByWhereJson = async (whereJson, fieldJson) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.findByWhereJson({
		dbName: dbName.order,
		whereJson,
		fieldJson
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 增 - 添加一条记录
 * @param {Object} dataJson 添加的数据
 * 调用示例
await vk.daoCenter.orderDao.add({

});
或
 * 调用示例
await vk.daoCenter.orderDao.add({
	db: transaction,
	dataJson: {

	}
});
 */
dao.add = async (obj) => {
	let { vk, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	if (obj.db && obj.dataJson) {
		// 支持事务
		res = await vk.baseDao.add({
			...obj,
			dbName: dbName.order,
		});
	} else {
		// 不支持事务
		res = await vk.baseDao.add({
			dbName: dbName.order,
			dataJson: obj
		});
	}
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 增 - 添加多条记录
 * @params {Object} dataJson 添加的数据
 * 调用示例
await vk.daoCenter.orderDao.adds(dataArr);
 */
dao.adds = async (dataArr) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.adds({
		dbName: dbName.order,
		dataJson: dataArr
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 删 - 删除多条记录
 * @params {Object} whereJson 条件
 * 调用示例
await vk.daoCenter.orderDao.del({

});
 */
dao.del = async (whereJson) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.del({
		dbName: dbName.order,
		whereJson
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 删 - 据ID删除单条数据
 * @params {String} id
 * 调用示例
await vk.daoCenter.orderDao.deleteById(id);
 */
dao.deleteById = async (id) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.deleteById({
		dbName: dbName.order,
		id
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 改 - 批量修改
 * @params {Object} whereJson 条件
 * @params {Object} dataJson 修改的数据
 * 调用示例
await vk.daoCenter.orderDao.update({
	whereJson:{

	},
	dataJson:{

	}
});
 */
dao.update = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.update({
		...obj,
		dbName: dbName.order,
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 改 - 根据ID修改数据
 * @params {String} id
 * @params {Object} dataJson 修改的数据
 * 调用示例
await vk.daoCenter.orderDao.updateById({
	id:id,
	dataJson:{

	}
});
 */
dao.updateById = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.updateById({
		dbName: dbName.order,
		...obj
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 改 - 更新并返回更新后的数据（无论条件匹配到多少条记录，只会修改第一条记录，同时返回修改后的数据）
 * @params {Object} whereJson 条件
 * @params {Object} dataJson 修改的数据
 * 调用示例
await vk.daoCenter.orderDao.updateAndReturn({
	whereJson:{

	},
	dataJson:{

	}
});
 */
dao.updateAndReturn = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.updateAndReturn({
		...obj,
		dbName: dbName.order
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 获取记录总条数
 * @params {Object} whereJson 条件
 * 调用示例
await vk.daoCenter.orderDao.count(whereJson);
 */
dao.count = async (whereJson) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.count({
		dbName: dbName.order,
		whereJson
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 获取记录总条数
 * @params {Object} whereJson 条件
 * 调用示例
await vk.daoCenter.orderDao.sum({
	fieldName: "",
	whereJson: {

	}
});
 */
dao.sum = async (obj) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.sum({
		...obj,
		dbName: dbName.order,
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 获取数据列表
 * 调用示例
let orderList = await vk.daoCenter.orderDao.select({
	pageIndex:1,
	pageSize:20,
	getMain:false,
	whereJson:{

	},
	fieldJson:{},
	sortArr:[{ "name":"_id", "type":"desc" }],
});
 */
dao.select = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.select({
		...obj,
		dbName: dbName.order
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 获取数据列表
 * 调用示例
let orderList = await vk.daoCenter.orderDao.selects({
	pageIndex:1,
	pageSize:20,
	getMain:false,
	whereJson:{

	},
	fieldJson:{},
	sortArr:[{ "name":"_id", "type":"desc" }],
	// 副表列表
	foreignDB:[
		{
			dbName:"副表表名",
			localKey:"主表外键名",
			foreignKey:"副表外键名",
			as:"副表as字段",
			limit:1
		}
	]
});
 */
dao.selects = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.selects({
		...obj,
		dbName: dbName.order
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 获取数据列表
 * 调用示例
res = await vk.daoCenter.orderDao.getTableData({ data });
 */
dao.getTableData = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.getTableData({
		...obj,
		dbName: dbName.order
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 订单count按status分组（client端）
 * 调用示例 let groupArr = await vk.daoCenter.orderDao.groupCountOrderByUserId(uid);
 */
dao.groupCountOrderByUserId = async (uid = "___", data) => {
	let { vk, db, _ } = util;
	const $ = db.command.aggregate;
	// 数据库操作开始-----------------------------------------------------------
	if (!data) {
		data = {
			pagination: {},
			formData: {}
		}
	}
	data.pagination = {
		pageIndex: 1,
		pageSize: 50
	};
	let list = await vk.daoCenter.orderDao.getTableData({
		data,
		getMain: true,
		getCount: false,
		// 主表where条件
		whereJson: {
			user_id: uid
		},
		groupJson: {
			_id: "$status",
			count: _.$.sum(1),
		},
		sortArr: [{ name: "_id", type: "asc" }],
	});
	let res = {
		"已关闭": 0,
		"已全额退款": 0,
		"售后": 0,
		"申请退款中": 0,
		"已取消": 0,
		"未付款": 0,
		"待付款": 0,
		"已付款": 0,
		"待发货": 0,
		"准备发货中": 0,
		"已全部发货": 0,
		"待收货": 0,
		"待发货": 0,
		"已收货": 0,
		"待评价": 0,
		"已使用": 0,
		"已完成": 0,
		"待完成": 0,
		"待收货": 0,
		"待使用": 0
	};
	for (let i in list) {
		let item = list[i];
		res[item._id] = item.count;
		if ([-4].indexOf(item._id) > -1) {
			res["已关闭"] += item.count;
		}
		if ([-3].indexOf(item._id) > -1) {
			res["已全额退款"] += item.count;
		}
		if ([-2].indexOf(item._id) > -1) {
			res["售后"] += item.count;
			res["申请退款中"] += item.count;
		}
		if ([-1].indexOf(item._id) > -1) {
			res["已取消"] += item.count;
		}
		if ([0].indexOf(item._id) > -1) {
			res["未付款"] += item.count;
			res["待付款"] += item.count;
		}
		if ([1].indexOf(item._id) > -1) {
			res["已付款"] += item.count;
			res["待发货"] += item.count;
		}
		if ([2].indexOf(item._id) > -1) {
			res["准备发货中"] += item.count;
			res["待发货"] += item.count;
		}
		if ([3].indexOf(item._id) > -1) {
			res["已部分发货"] += item.count;
			res["待收货"] += item.count;
		}
		if ([4].indexOf(item._id) > -1) {
			res["已全部发货"] += item.count;
			res["待收货"] += item.count;
			res["待使用"] += item.count;
		}
		if ([5].indexOf(item._id) > -1) {
			res["已收货"] += item.count;
			res["待评价"] += item.count;
			res["已使用"] += item.count;
		}
		if ([6].indexOf(item._id) > -1) {
			res["已完成"] += item.count;
			res["已使用"] += item.count;
		}
		if ([1, 2, 3, 4, 5].indexOf(item._id) > -1) {
			res["待完成"] += item.count;
		}
	}
	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 订单count按status分组（admin端）
let groupArr = await vk.daoCenter.orderDao.groupCountOrderForStatus({

}, data);
 */
dao.groupCountOrderForStatus = async (whereJson, data) => {
	let { vk, db, _ } = util;
	const $ = db.command.aggregate;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	if (!data) {
		data = {
			pagination: {},
			formData: {}
		}
	}
	data.pagination = {
		pageIndex: 1,
		pageSize: 50
	};
	let list = await vk.daoCenter.orderDao.getTableData({
		data,
		getMain: true,
		getCount: false,
		// 主表where条件
		whereJson,
		groupJson: {
			_id: "$status",
			count: _.$.sum(1),
		},
		sortArr: [{ name: "_id", type: "asc" }],
	});
	for (let i in list) {
		let item = list[i];
		res[item._id] = item.count;
	}
	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 添加购物车(商品购买)记录
 * 调用示例
await vk.daoCenter.orderDao.addCartRecords({
	dataArr : dataArr,
});
 */
// dao.addCartRecords = async (orderInfo) => {
// 	let { vk, db, _ } = util;
// 	let res = { code: 0, msg: "" };
// 	// 数据库操作开始-----------------------------------------------------------
// 	let {
// 		_id,
// 		goods_sku_list
// 	} = orderInfo;
// 	let dataArr = [];
// 	for (let i in goods_sku_list) {
// 		let item = goods_sku_list[i];
// 		// 记录需要记录的字段
// 		let sku_info = {
// 			market_price: item.market_price, // 市场价
// 			price: item.price, // 原价(单价)
// 			sku_name: item.sku_name, // sku名称
// 			weight: item.weight, // 重量
// 			total_amount: item.total_amount, // 原价合计
// 			should_payment_amount: item.should_payment_amount, // 应付合计
// 			vip: item.vip, // 使用的会员等级
// 			used_coupon_id: item.used_coupon_id, // 使用的优惠券id
// 			vip_discount_amount: item.vip_discount_amount, // vip优惠金额
// 			coupon_discount_amount: item.coupon_discount_amount, // 优惠券优惠金额
// 			business_discount_amount: item.business_discount_amount, // 商家优惠金额
// 		};
// 		// 记录需要记录的字段
// 		dataArr.push({
// 			order_id: _id, // 订单id
// 			sku_info: sku_info, // sku信息（冗余）
// 			goods_id: item.goods_id, // 商品id
// 			goods_name: item.goods_name, // 商品名称
// 			image: item.image, // 图片
// 			sku_id: item._id, // sku_id
// 			user_id: orderInfo.user_id, // 用户id
// 			buyer_info: orderInfo.buyer_info, // 购买者信息(昵称和头像)
// 			status: orderInfo.status, // 状态
// 			buy_num: item.buy_num, // 购买数量
// 			send_num: orderInfo.status == "is_send_all" ? item.buy_num : 0, // 已发货数量
// 			pay_time: orderInfo.pay_time, // 付款时间
// 			send_time: orderInfo.send_time, // 发货时间
// 		});
// 	}
// 	await vk.baseDao.adds({
// 		dbName: dbName.cart,
// 		dataJson: dataArr
// 	});
// 	// 数据库操作结束-----------------------------------------------------------
// 	return res;
// };

/**
 * 取消订单，并返回取消后的订单信息
let orderInfo = await vk.daoCenter.orderDao.cancelOrder({
	order_no,
	user_id: uid,
	oper_type: "my",
	oper_uid: uid
});
 */
dao.cancelOrder = async (obj) => {
	let { vk, db, _ } = util;
	let res = {};
	let {
		oper_uid,
		oper_type = "my",
		order_no = "___",
		user_id = "___",
	} = obj;
	// 数据库操作开始-----------------------------------------------------------
	let time = Date.now();
	let timeline;
	if (oper_type == "my") {
		timeline = { time, msg: "用户取消订单", type: "cancel", oper_type, oper_uid };
	} else if (oper_type == "overtime") {
		timeline = { time, msg: "超时自动取消订单", type: "cancel", oper_type, oper_uid };
	} else {
		timeline = { time, msg: "系统取消订单", type: "cancel", oper_type, oper_uid };
	}
	// 开启事务
	const transaction = await vk.baseDao.startTransaction();
	try {
		res = await dao.updateAndReturn({
			db: transaction,
			whereJson: {
				order_no,
				user_id,
				status: 0, // 只有未付款的订单才可以取消
			},
			dataJson: {
				status: -1,
				cancel_time: time,
				timeline: _.push(timeline)
			}
		});
		if (res.amount_info.used_balance_amount > 0) {
			// 恢复余额（因为有可能是用户余额+微信支付，然后在微信支付环节不付款导致订单取消，此时需要将余额退回用户的余额账户中
			await vk.daoCenter.moneyDao.updateAccountBalanceForTransaction({
				db: transaction,
				user_id: user_id,
				value: res.amount_info.used_balance_amount, // 此值始终为正整数 100=1元
				isAdd: true, // true 增加 false 减少
				no: order_no,
				title: timeline.msg,
				comment: ``,
				add_type: 4, // 1 人工录入 2 用户线上充值 3 消费 4 退款 5 转账 6 余额转换 7 奖励发放 8 解锁 9 提现 10 提现拒绝后返还
				updateTotal: false,
			});
		}
		if (res.amount_info.used_integral > 0) {
			// 恢复积分（如果用户下单使用了积分，此时需要将积分退回用户的积分账户中）
			await vk.daoCenter.moneyDao.updateAccountIntegralForTransaction({
				db: transaction,
				user_id: user_id,
				value: res.amount_info.used_integral, // 此值始终为正整数 100=1元
				isAdd: true, // true 增加 false 减少
				no: order_no,
				title: timeline.msg,
				comment: ``,
				add_type: 4, // 1 人工录入 2 用户线上充值 3 消费 4 退款 5 转账 6 余额转换 7 奖励发放 8 解锁 9 提现 10 提现拒绝后返还
				updateTotal: false,
			});
		}
		// 提交事务
		await transaction.commit();
		console.log(`transaction succeeded`);
		// 以下操作不使用事务
		if (res) {
			let used_coupon_id = vk.pubfn.getData(res, "discount_info.used_coupon_id");
			if (used_coupon_id) {
				// 还原优惠券
				await vk.daoCenter.userCouponDao.resetCouponsById(used_coupon_id);
			}
			if (res.goods_sku_list) {
				// 恢复库存
				await vk.daoCenter.goodsDao.addSkuStockByskuList(res.goods_sku_list);
			}
		}
	} catch (err) {
		// 事务回滚
		return await vk.baseDao.rollbackTransaction({
			db: transaction,
			err
		});
	}
	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 自动取消已过期未付款订单
 * @params {String} id
 * @params {Object} dataJson 修改的数据
 * 调用示例
await vk.daoCenter.orderDao.autoCancelOrder({
	user_id: uid
});
 */
dao.autoCancelOrder = async (obj = {}) => {
	let { vk, db, _ } = util;
	let num = 0;
	// 数据库操作开始-----------------------------------------------------------
	let {
		user_id = "___"
	} = obj;
	let time = Date.now();
	let timeline = { time, msg: "超时自动取消订单", type: "cancel", oper_type: "system", oper_uid: "system" };
	num = await dao.update({
		whereJson: {
			user_id, // 自己的订单
			status: 0, // 未付款的订单
			auto_cancel_time: _.lte(time), // 到了自动取消的时间
			"amount_info.used_balance_amount": 0, // 用户未使用余额进行部分付款过
			"amount_info.used_integral": _.or(_.exists(false), _.eq(0)), // 用户未使用积分抵扣过
		},
		dataJson: {
			status: -1,
			cancel_time: time,
			timeline: _.push(timeline)
		}
	});
	// 查询在cancel_time时间取消的订单，重置优惠券
	if (num > 0) {
		let list = await dao.select({
			getCount: false,
			getMain: true,
			pageIndex: 1,
			pageSize: num,
			whereJson: {
				user_id,
				status: -1,
				cancel_time: time,
			},
		});
		let usedCouponIds = [];
		list.map((item, index) => {
			let used_coupon_id = vk.pubfn.getData(item, "discount_info.used_coupon_id");
			if (used_coupon_id) {
				usedCouponIds.push(used_coupon_id);
			}
		});
		// 重置优惠券
		await vk.daoCenter.userCouponDao.resetCouponsById(usedCouponIds);
	}
	// 如果还有未付款订单（一般是有余额付款部分，或积分抵扣，此时需要一个一个取消，因为要退余额、积分、优惠券）
	let orderList = await dao.select({
		getCount: false,
		getMain: true,
		pageIndex: 1,
		pageSize: 10, // 为了不影响性能，此处设为10
		whereJson: {
			user_id,
			status: 0, // 只有未付款的订单才可以取消
			auto_cancel_time: _.lte(time)
		}
	});
	if (vk.pubfn.isNotNull(orderList)) {
		// 循环遍历一个一个取消订单，原因为：有余额付款部分，或积分抵扣，此时需要一个一个取消，因为要退余额、积分、优惠券
		for (let i = 0; i < orderList.length; i++) {
			let item = orderList[i];
			let cancelRes = await dao.cancelOrder({
				order_no: item.order_no, // 订单号
				user_id: user_id, // 用户id
				author: "system", // 操作员：系统
			});
			if (cancelRes) {
				num++;
			}
		}
	}
	console.log(`成功取消 ${num} 个订单`);
	// 数据库操作结束-----------------------------------------------------------
	return num;
};


/**
 * 用户申请退款(支持部分退款)
 * 调用示例
let applyRefundRes = await vk.daoCenter.orderDao.applyRefund({
	orderInfo,
	oper_type: "my",
	oper_uid,
	refund_reason,
	refund_desc,
	images
});
 */
dao.applyRefund = async (obj = {}) => {
	let { vk, db, _ } = util;
	let {
		mchInfo, // 商户信息
		orderInfo, // 订单信息
		oper_type = "my", // 操作人类型 my 由客户自己发起 business 由商家发起 system 由系统发起
		oper_uid, // 操作人uid
		refund_reason, // 退款原因
		refund_desc, // 退款说明（用户备注）
		images, // 用户上传的图片，如快递面单等
		goods_sku_list, // 退款商品列表
		express_name, // 寄回的快递公司名称
		express_no, // 寄回的快递公司单号
		refund_express_amount, // 退运费金额
		is_auto_refund = 0, // 1 自动审核通过
	} = obj;

	// 数据库操作开始-----------------------------------------------------------
	let { refund_num = 0 } = orderInfo;
	let out_refund_no = `${orderInfo.order_no}-${refund_num+1}`;
	let goods_list = [];
	let refund_amount = 0; // 合计退款金额
	let refund_goods_amount = 0; // 合计退款商品金额
	// 循环退款商品列表,计算退款金额
	goods_sku_list.map((item, index) => {
		let goodsInfo = vk.pubfn.getListItem(orderInfo.goods_sku_list, "_id", item._id);
		let crr_refund_amount = 0;
		if (item.refund_amount) {
			// 如果有传固定的退款金额，则使用固定的退款金额
			crr_refund_amount = item.refund_amount;
		} else {
			// 否则根据退款数量计算退款金额 = 退款数量 / 购买数量 * 付款金额
			crr_refund_amount = vk.pubfn.toDecimal(item.refund_num / goodsInfo.buy_num * goodsInfo.should_payment_amount, 0);
			// 当前商品的退款金额不可以大于最大可退款金额
			// 最大可退款金额 = 付款金额 - 已退款金额
			let refund_amount = goodsInfo.refund_amount || 0;
			let maxAmount = goodsInfo.should_payment_amount - refund_amount;
			if (crr_refund_amount > maxAmount) {
				crr_refund_amount = maxAmount;
			}
		}

		goods_list.push({
			sku_id: item._id, // skuId
			refund_num: item.refund_num, // 退款数量
			refund_amount: crr_refund_amount, // 退款金额
			payment_amount: goodsInfo.should_payment_amount, // 商品当时的付款金额
			buy_num: goodsInfo.buy_num, // 商品当时的购买数量
			buy_info: goodsInfo, // 购买时的商品信息
		});
		refund_goods_amount += crr_refund_amount; // 合计退款商品金额
	});


	// 计算是否已全部退款
	let isFullRefund = 1;
	orderInfo.goods_sku_list.map((item, index) => {
		let refundItem = vk.pubfn.getListItem(goods_sku_list, "_id", item._id);
		let { buy_num, refund_num = 0 } = item;
		if (refundItem && refundItem.refund_num) {
			refund_num += refundItem.refund_num;
		}
		if (buy_num - refund_num > 0) {
			// 未全部退款
			isFullRefund = 0;
		}
	});
	if (isFullRefund == 1 && typeof refund_express_amount === "undefined") {
		// 如果是全额退款，且未指定退运费的金额，则默认退全部运费
		// 当前最大可退运费金额 = 订单运费金额 - 已退款的运费金额
		let maxRefundExpressAmount = orderInfo.amount_info.express_amount - orderInfo.amount_info.refund_express_amount;
		refund_express_amount = maxRefundExpressAmount;
	}
	// 如果此时refund_express_amount值还是空，则赋值为0
	if (!refund_express_amount) refund_express_amount = 0;
	// 合计退款金额 = 合计退款商品 + 退款运费
	refund_amount = refund_goods_amount + refund_express_amount;

	// 合计退款金额 不可以大于最大可退款金额
	let maxRefundAmount = orderInfo.amount_info.payment_amount - orderInfo.amount_info.refund_amount;
	if (refund_amount > maxRefundAmount) return { code: -1, msg: `订单最大可退金额为:${vk.pubfn.toDecimal(maxRefundAmount / 100, 2)}` };

	// console.log('isFullRefund: ', isFullRefund)
	// console.log('refund_amount: ', refund_amount)
	// console.log('refund_goods_amount: ', refund_goods_amount)
	// console.log('refund_express_amount: ', refund_express_amount)
	// return {};

	let time = Date.now();
	let timeline;
	if (oper_type == "my") {
		timeline = { time, msg: "用户申请退款", type: "applyRefund", oper_type, oper_uid };
		let integral = await vk.daoCenter.orderDao.calcRefundGiveIntegral({
			refund_goods_list: goods_list,
			update: false, // 是否会更新goods_list内的refund_give_integral
		});
		let userInfo = await vk.daoCenter.userDao.findById(orderInfo.user_id);
		if (userInfo.account_integral.balance < integral) {
			return { code: -1, msg: `申请失败，您的积分不足，因本次退款需要扣除【${integral}】个积分，由于您目前只有【${userInfo.account_integral.balance}】个积分，故不可申请退款。` };
		}
	} else {
		timeline = { time, msg: "商家主动退款", type: "applyRefund", oper_type: "business", oper_uid };
	}

	let res = { code: 0, msg: "" };
	// 开启事务
	const transaction = await vk.baseDao.startTransaction();
	try {
		// 为了防止用户恶意下单再退款，故退款需要后台审核，故修改订单状态为退款申请中
		res.orderInfo = await vk.baseDao.updateAndReturn({
			db: transaction,
			dbName: dbName.order,
			whereJson: {
				_id: orderInfo._id,
				status: _.in([1, 3, 4, 5]),
			},
			dataJson: {
				status: -2, // 状态修改为申请退款中
				enable_delivery: false, // 申请退款中，标记订单不可发货
				refund_num: _.inc(1), // 申请退款次数
				apply_refund_time: time, // 申请退款时间
				timeline: _.push(timeline), // 时间线
				out_refund_no, // 记录最新的退款单号
			},
		});
		if (res.orderInfo) {
			// 添加订单退款申请记录
			await vk.baseDao.add({
				db: transaction,
				dbName: dbName.orderRefund,
				dataJson: {
					status: 0,
					order_status: orderInfo.status, // 申请退款前的订单状态
					user_id: orderInfo.user_id,
					order_id: orderInfo._id,
					order_no: orderInfo.order_no,
					out_refund_no,
					refund_type: 1,
					refund_reason,
					refund_method: 0,
					refund_amount,
					refund_goods_amount,
					refund_express_amount,
					refund_desc,
					images,
					apply_refund_time: time, // 申请退款时间
					goods_list,
					express_name, // 寄回的快递公司名称
					express_no, // 寄回的快递公司单号
					is_auto_refund
				}
			});
		}
		// 提交事务
		await transaction.commit();
		console.log(`transaction succeeded`);
	} catch (err) {
		// 事务回滚
		return await vk.baseDao.rollbackTransaction({
			db: transaction,
			err
		});
	}
	console.log('is_auto_refund: ', is_auto_refund)
	if (is_auto_refund === 1) {
		let orderRefundExamineRes = await vk.daoCenter.orderDao.orderRefundExamine({
			order_id: orderInfo._id, // 订单id
			oper_uid: oper_uid, // 操作人uid
			type: 1, // 1 同意退款 2 拒绝退款
			out_refund_no, // 退款单号
			goods_list, // 退款商品数量和金额信息
			refund_express_amount, // 运费退款金额
			status_msg: "审核通过", // 退款说明
		});
		if (orderRefundExamineRes.code == 0) {
			res.msg = orderRefundExamineRes.msg;
			res.orderInfo = orderRefundExamineRes.orderInfo;
		} else {
			res.msg = "已提交退款申请！请等待商家同意后才能退款！";
		}
	} else {
		res.msg = "已提交退款申请！请等待商家同意后才能退款！";
	}

	// 数据库操作结束-----------------------------------------------------------
	return res;
};



/**
 * 订单退款审核
 * 调用示例
await vk.daoCenter.orderDao.orderRefundExamine({
	order_id, // 订单id
	oper_uid: uid, // 操作人uid
	type, // 1 同意退款 2 拒绝退款
	out_refund_no, // 退款单号
	goods_list, // 退款商品数量和金额信息
	refund_express_amount, // 运费退款金额
	status_msg, // 退款说明
});
 */
dao.orderRefundExamine = async (data = {}) => {
	let { vk, _ } = util;
	let res = { code: 0, msg: '' };
	let {
		order_id, // 订单id
		oper_uid,
		type, // 1 同意退款 2 拒绝退款
		out_refund_no, // 退款单号
		goods_list, // 退款商品数量和金额信息
		refund_express_amount, // 运费退款金额
		status_msg, // 退款说明
	} = data;
	// 参数非空检测
	let nullKey = vk.pubfn.isNullOneByObject({ order_id, type, out_refund_no, goods_list });
	if (nullKey) return { code: -1, msg: '参数 ' + nullKey + ' 不能为空' };
	// 订单信息
	let orderInfo = await vk.daoCenter.orderDao.findById(order_id);
	if (vk.pubfn.isNull(orderInfo)) return { code: -1, msg: "订单不存在" };
	if (orderInfo.status !== -2) return { code: -1, msg: "订单不在申请退款状态中" };
	let {
		order_no,
		goods_sku_list,
		pay_type
	} = orderInfo;
	// 获取退款详情
	let refundInfo = await vk.daoCenter.orderRefundDao.findByWhereJson({
		order_id,
		out_refund_no,
	});
	if (vk.pubfn.isNull(refundInfo)) return { code: -1, msg: "退款申请单不存在" };

	// 最终以前端传过来的 goods_list 为准，因为工作人员可能会修改用户提交的信息
	// 重新计算商品退款金额
	// 更新退款单上的退款数量和金额
	let refund_goods_amount = 0;
	refundInfo.goods_list.map((item, index) => {
		let goods = vk.pubfn.getListItem(goods_list, "sku_id", item.sku_id);
		item.refund_num = goods.refund_num;
		item.refund_amount = goods.refund_amount;
		refund_goods_amount += item.refund_amount;
	});

	if (!refund_express_amount) refund_express_amount = 0;
	// 实际退款金额 = 商品金额 + 运费
	let refund_amount = vk.pubfn.toDecimal(refund_goods_amount + refund_express_amount, 0);

	let time = Date.now();
	let isNumFullRefund = 1; // 0 部分退款 1 全额退款
	let isAmountFullRefund = 1; //  0 部分退款 1 全额退款
	let updateOrderStatus;
	let timeline;

	let reality_refund_cash_amount = 0; // 最终退款现金金额
	let reality_refund_balance_amount = 0; // 最终退款账户余额
	let reality_refund_give_integral = 0; // 最终需要扣除的积分
	let reality_refund_used_integral = 0; // 最终需要退款的积分
	/**
	 * 当同时有现金和余额支付时的退款策略：
	 * 优先退现金，现金全部退完再退余额
	 * 如果订单使用了优惠券，优惠券仅在全额退款时才会退还
	 * 如果订单使用了积分，积分按实际退款金额比例退还
	 */
	let updateDataJson = {};
	if (type === 1) {
		// 如果订单使用了积分，积分按实际退款金额比例退还（即商品设置了允许积分抵扣时）
		reality_refund_used_integral = await vk.daoCenter.orderDao.calcRefundUsedIntegral({
			refund_goods_list: refundInfo.goods_list,
			update: true
		});
		// 如果涉及到积分奖励，积分按实际退款金额比例扣除（即商品设置了付款得积分时）
		reality_refund_give_integral = await vk.daoCenter.orderDao.calcRefundGiveIntegral({
			refund_goods_list: refundInfo.goods_list,
			update: true
		});
		let userInfo = await vk.daoCenter.userDao.findById(orderInfo.user_id);
		if (userInfo.account_integral.balance < reality_refund_give_integral) {
			reality_refund_give_integral = userInfo.account_integral.balance; // 若用户积分不足，则清0
		}
		// 当前最大可退运费金额
		let maxRefundExpressAmount = orderInfo.amount_info.express_amount - orderInfo.amount_info.refund_express_amount;
		if (refund_express_amount > maxRefundExpressAmount) return { code: -1, msg: `订单最大可退运费为:${vk.pubfn.toDecimal(maxRefundExpressAmount / 100, 2)}` };
		if (refund_amount < 0) return { code: -1, msg: "退款金额不能小于0" };
		// 当前最大可退款金额 = 订单实付金额 - 订单已退金额
		let maxRefundAmount = orderInfo.amount_info.payment_amount - orderInfo.amount_info.refund_amount;
		if (refund_amount > maxRefundAmount) return { code: -1, msg: `订单最大可退金额为:${vk.pubfn.toDecimal(maxRefundAmount / 100, 2)}` };
		// 申请金额和数量判断
		let errMsg;
		// 遍历商品sku，计算当前是全额退款还是部分退款，同时判断是否允许退款
		goods_sku_list.map((item, index) => {
			let maxRefunNum = item.buy_num - item.refund_num;
			let maxRefunAmount = item.should_payment_amount - item.refund_amount;
			let goods = vk.pubfn.getListItem(refundInfo.goods_list, "sku_id", item.sku_id);
			if (goods) {
				if (goods.refund_num > maxRefunNum) {
					errMsg = `商品【${item.goods_name}-${item.sku_name}】最大可退数量为：${maxRefunNum}，而你申请的数量为：${goods.refund_num}`;
				} else if (goods.refund_amount > maxRefunAmount) {
					errMsg =
						`商品【${item.goods_name}-${item.sku_name}】最大可退金额为：${vk.pubfn.priceFilter(maxRefunAmount)}，而你申请的金额为：${vk.pubfn.priceFilter(goods.refund_amount)}`;
				}
				if (goods.refund_num < maxRefunNum) {
					isNumFullRefund = 0; // 部分退款
				}
				if (goods.refund_amount < maxRefunAmount) {
					isAmountFullRefund = 0; // 部分退款
				}
			} else {
				if (maxRefunNum > 0) {
					isNumFullRefund = 0; // 部分退款
				}
				if (maxRefunAmount > 0) {
					isAmountFullRefund = 0; // 部分退款
				}
			}
		});
		if (errMsg) return { code: -1, msg: errMsg };

		if (isNumFullRefund === 0) {
			// 部分退款
			// 部分退款成功后，订单状态需要还原成之前申请退款前的订单状态
			updateOrderStatus = refundInfo.order_status;
		} else {
			// 全额退款
			// 如果商品金额也已退完，则标记全额退款，否则直接标记已完成(因为商品数量已全部退款，代表无需发货，所以直接已完成)
			updateOrderStatus = isAmountFullRefund == 1 ? -3 : 6;
			let mchInfo = await vk.daoCenter.mchDao.find();
			let day = vk.pubfn.getData(mchInfo, "order.auto_complete", 7);
			let auto_complete_time = time + 1000 * 3600 * 24 * day; // X天后自动关闭
			updateDataJson["auto_complete_time"] = auto_complete_time;
		}
		// 订单时间线
		timeline = { time: time, msg: "商家同意退款", type: "refund", oper_type: "business", oper_uid: oper_uid };

		console.log("开始金额的退款计算");
		console.log('本次共退款金额: ', vk.pubfn.toDecimal(refund_amount / 100, 2), "refund_amount");
		// 计算需要退款的现金
		let refundAmountDiff = refund_amount;
		// 当前可退款现金 = 总支付现金 - 已退款现金
		let maxRefundCashAmount = orderInfo.amount_info.used_cash_amount - orderInfo.amount_info.refund_cash_amount;
		console.log('本次最大可退款现金: ', vk.pubfn.toDecimal(maxRefundCashAmount / 100, 2), 'maxRefundCashAmount')
		if (maxRefundCashAmount > 0 && refundAmountDiff > 0) {
			// 如果本次退款总金额大于最大可退款的现金金额，则实际退现金 = 最大现金退款金额
			reality_refund_cash_amount = refundAmountDiff > maxRefundCashAmount ? maxRefundCashAmount : refundAmountDiff;
			refundAmountDiff -= reality_refund_cash_amount;
		}

		// 计算需要退款的余额
		// 当前可退款余额 = 总支付余额 - 已退款余额
		let maxRefundBalanceAmount = orderInfo.amount_info.used_balance_amount - orderInfo.amount_info.refund_balance_amount;
		console.log('本次最大可退款余额: ', vk.pubfn.toDecimal(maxRefundBalanceAmount / 100, 2), 'maxRefundBalanceAmount')
		if (maxRefundBalanceAmount > 0 && refundAmountDiff > 0) {
			reality_refund_balance_amount = refundAmountDiff > maxRefundBalanceAmount ? maxRefundBalanceAmount : refundAmountDiff;
			refundAmountDiff -= reality_refund_balance_amount;
		}
		console.log('还剩多少金额没退: ', vk.pubfn.toDecimal(refundAmountDiff / 100, 2), 'refundAmountDiff')
		// 正常情况下，此值一定会 = 0，如果不是，代表该退款接口内部有bug。
		if (refundAmountDiff !== 0) {
			return { code: -1, msg: `系统检测到订单号【${order_no}】退款金额异常，请联系管理员检查！` };
		}

		// 订单需要增加已退款金额
		if (refund_amount) updateDataJson["amount_info.refund_amount"] = _.inc(refund_amount); // 增加退款金额
		if (reality_refund_balance_amount) updateDataJson["amount_info.refund_balance_amount"] = _.inc(reality_refund_balance_amount); // 增加退款余额
		if (reality_refund_cash_amount) updateDataJson["amount_info.refund_cash_amount"] = _.inc(reality_refund_cash_amount); // 增加退款现金
		if (refund_express_amount) updateDataJson["amount_info.refund_express_amount"] = _.inc(refund_express_amount); // 增加退款运费
		if (reality_refund_give_integral) updateDataJson["amount_info.refund_give_integral"] = _.inc(reality_refund_give_integral); // 增加已退款的奖励积分
		if (reality_refund_used_integral) updateDataJson["amount_info.refund_used_integral"] = _.inc(reality_refund_used_integral); // 增加已退款的已使用积分

		for (let i = 0; i < refundInfo.goods_list.length; i++) {
			let goodsItem = refundInfo.goods_list[i];
			let index = vk.pubfn.getListIndex(goods_sku_list, "_id", goodsItem.sku_id);
			if (goodsItem.refund_num) updateDataJson[`goods_sku_list.${index}.refund_num`] = _.inc(goodsItem.refund_num); // 增加该商品的退款数量
			if (goodsItem.refund_amount) updateDataJson[`goods_sku_list.${index}.refund_amount`] = _.inc(goodsItem.refund_amount); // 增加该商品的退款金额
			if (goodsItem.refund_give_integral) updateDataJson[`goods_sku_list.${index}.refund_give_integral`] = _.inc(goodsItem.refund_give_integral); // 增加该商品的退款积分
		}
	} else {
		// 拒绝退款，拒绝退款后订单状态需要恢复到申请退款前的状态
		updateOrderStatus = refundInfo.order_status;
		res.msg = "操作成功，已拒绝退款。";
		timeline = { time: time, msg: "商家拒绝退款", type: "cancelRefund", oper_type: "business", oper_uid: oper_uid };
	}

	if ([1, 2, 3, 4].indexOf(updateOrderStatus) > -1) {
		updateDataJson["enable_delivery"] = true;
	}

	let dataJson = {
		status: updateOrderStatus,
		refund_time: time,
		timeline: _.push(timeline),
		...updateDataJson
	};

	// 开启事务
	const transaction = await vk.baseDao.startTransaction();
	try {
		console.log("修改订单状态");
		orderInfo = await vk.daoCenter.orderDao.updateAndReturn({
			db: transaction,
			whereJson: {
				_id: order_id,
				status: -2,
			},
			dataJson
		});
		if (!orderInfo) {
			return { code: -1, msg: "操作失败，订单状态错误" };
		}
		// 修改退款申请单
		await vk.baseDao.updateById({
			db: transaction,
			dbName: dbName.orderRefund,
			id: refundInfo._id,
			dataJson: {
				status: type === 1 ? 2 : -1,
				status_time: time,
				status_msg,
				goods_list: _.set(refundInfo.goods_list)
			}
		});

		if (type === 1) {
			// 如果是同意退款，需要进行金额的退款处理
			console.log("开始金额的退款处理");
			// 余额支付的部分退余额
			console.log('实际退款余额: ', vk.pubfn.toDecimal(reality_refund_balance_amount / 100, 2), 'reality_refund_balance_amount')
			if (reality_refund_balance_amount > 0) {
				await vk.daoCenter.moneyDao.updateAccountBalanceForTransaction({
					db: transaction,
					user_id: orderInfo.user_id,
					value: reality_refund_balance_amount, // 此值始终为正整数 100=1元
					isAdd: true, // true 增加 false 减少
					no: order_no,
					title: `订单退款余额返还`,
					comment: ``,
					add_type: 4, // 1 人工录入 2 用户线上充值 3 消费 4 退款 5 转账 6 余额转换 7 奖励发放 8 解锁 9 提现 10 提现拒绝后返还
					updateTotal: false, // 因为是退款，故不增加 累计充值
					updateUsed: true, // 因为是退款，故减少 累计已使用
				});
			}
			// 如果使用了积分抵扣，则退回积分（退回积分需要在扣除积分奖励的前面执行）
			if (reality_refund_used_integral > 0) {
				console.log('实际退回积分: ', reality_refund_used_integral, 'reality_refund_used_integral')
				await vk.daoCenter.moneyDao.updateAccountIntegralForTransaction({
					db: transaction,
					user_id: orderInfo.user_id,
					value: reality_refund_used_integral, // 此值始终为正整数 100=1元
					isAdd: true, // true 增加 false 减少
					no: order_no,
					title: `订单退款退回已使用的积分`,
					comment: ``,
					add_type: 4, // 1 人工录入 2 用户线上充值 3 消费 4 退款 5 转账 6 余额转换 7 奖励发放 8 解锁 9 提现 10 提现拒绝后返还
					updateTotal: false,
				});
			}

			// 如果奖励了积分，则扣除积分奖励
			if (reality_refund_give_integral > 0) {
				console.log('实际扣除积分: ', reality_refund_give_integral, 'reality_refund_give_integral')
				await vk.daoCenter.moneyDao.updateAccountIntegralForTransaction({
					db: transaction,
					user_id: orderInfo.user_id,
					value: reality_refund_give_integral, // 此值始终为正整数 100=1元
					isAdd: false, // true 增加 false 减少
					no: order_no,
					title: `订单退款扣除奖励的积分`,
					comment: ``,
					add_type: 4, // 1 人工录入 2 用户线上充值 3 消费 4 退款 5 转账 6 余额转换 7 奖励发放 8 解锁 9 提现 10 提现拒绝后返还
					updateTotal: true,
				});
			}

			// 写入返利任务（需要扣除返利和业绩）
			console.log("写入返利任务")
			await vk.daoCenter.orderTaskDao.addOrderTask({
				db: transaction,
				dataJson: {
					type: 1002, // 1001 订单付款 1002 订单退款
					title: `订单【${order_no}】退款`,
					order_no: order_no, // 订单号
					out_refund_no: out_refund_no, //退款单号
				}
			});

			// 第三方支付的部分原路退回（第三方支付的退款放最后，因为事务回滚后不会回滚第三方退款的操作，所以尽量让他最后一个执行）
			console.log('实际退款现金: ', vk.pubfn.toDecimal(reality_refund_cash_amount / 100, 2), 'reality_refund_cash_amount')
			// 只有线上支付的订单才走线上退款
			if (pay_type !== "offline" && reality_refund_cash_amount > 0) {
				let refundRes = await vk.vkPay.refund({
					out_trade_no: order_no,
					out_refund_no: out_refund_no,
					refund_desc: "用户申请退款",
					refund_fee: reality_refund_cash_amount
				});
				if (refundRes.code !== 0) {
					// 事务回滚
					await transaction.rollback();
					return refundRes;
				}
			}
			// 退款成功发送通知
			res.msg = "退款成功，资金已原路退回。";
		}
		// 提交事务
		await transaction.commit();
		console.log(`transaction succeeded`);
	} catch (err) {
		// 事务回滚
		return await vk.baseDao.rollbackTransaction({
			db: transaction,
			err
		});
	}
	if (type === 1) {
		// 退款的商品库存增加，因为库存如果用事务会造成并发性能低，因此这里在事务外面执行
		console.log("退款的商品库存增加")
		await vk.daoCenter.goodsDao.addSkuStockByRefundGoodsList(refundInfo.goods_list);
		// 如果订单已经全额退款，且订单使用了优惠券，优惠券会退还
		if ([-3, -4].indexOf(orderInfo.status) > -1) {
			let used_coupon_id = vk.pubfn.getData(orderInfo, "discount_info.used_coupon_id");
			if (used_coupon_id) {
				// 还原优惠券
				console.log("还原优惠券")
				await vk.daoCenter.userCouponDao.resetCouponsById(used_coupon_id);
			}
		}
	}
	res.orderInfo = orderInfo;
	return res;
};





/**
 * 订单取消退款（将订单修改为已付款）
 * 调用示例
let newOrderInfo = await vk.daoCenter.orderDao.cancelRefund({
	orderInfo,
	oper_type: "my",
	oper_uid: uid
});
 */
dao.cancelRefund = async (obj = {}) => {
	let { vk, db, _ } = util;
	let {
		orderInfo,
		oper_type = "my",
		oper_uid,
	} = obj;
	// 数据库操作开始-----------------------------------------------------------
	let time = Date.now();
	let timeline;
	if (oper_type == "my") {
		timeline = { time, msg: "用户取消申请退款", type: "cancelRefund", oper_type, oper_uid };
	} else {
		timeline = { time, msg: "商家拒绝退款", type: "cancelRefund", oper_type: "business", oper_uid };
	}
	let { refund_num = 0, timeline: timelineList = [] } = orderInfo;
	// 为了防止用户不停的申请退款，取消退款，当用户取消退款时，不添加时间线，反而应该删除最新的一次申请退款时间线
	let lastIndex = 0;
	for (let i = 0; i < timelineList.length; i++) {
		let item = timelineList[i];
		if (item.type === "applyRefund") {
			lastIndex = i;
		}
	}
	timelineList.splice(lastIndex, 1);
	let res = await vk.baseDao.updateAndReturn({
		dbName: dbName.order,
		whereJson: {
			_id: orderInfo._id,
			status: -2
		},
		dataJson: {
			status: 1,
			enable_delivery: true, // 取消退款，可以发货
			apply_refund_time: _.remove(),
			timeline: _.set(timelineList), // 时间线
		},
	});
	await vk.baseDao.update({
		dbName: dbName.orderRefund,
		whereJson: {
			order_id: orderInfo._id,
			status: 0,
		},
		dataJson: {
			status: -2, // 退款状态 -2 用户取消退款 -1 商家拒绝退款 0 申请中 1 同意退款（退款中） 2 退款成功
		}
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 查 - 获取用户累计订单付款金额
 * 调用示例
let sumPaymentAmount = await vk.daoCenter.orderDao.sumPaymentAmount(uid);
 */
dao.sumPaymentAmount = async (uid) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.sum({
		dbName: dbName.order,
		fieldName: "amount_info.payment_amount",
		whereJson: {
			user_id: uid,
			status: _.gt(0)
		}
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 查 - 获取已确认收货+已完成的订单的订单金额
 * 调用示例
let sumReceiptAmount = await vk.daoCenter.orderDao.sumReceiptAmount(uid);
 */
dao.sumReceiptAmount = async (uid) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.sum({
		dbName: dbName.order,
		fieldName: "amount_info.payment_amount",
		whereJson: {
			user_id: uid,
			status: _.in([5, 6])
		}
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 查 - 获取未确认收货或未完成的订单的订单金额
 * 调用示例
let sumNotReceiptAmount = await vk.daoCenter.orderDao.sumNotReceiptAmount(uid);
 */
dao.sumNotReceiptAmount = async (uid) => {
	let { vk, db, _ } = util;
	let res = {};
	// 数据库操作开始-----------------------------------------------------------
	res = await vk.baseDao.sum({
		dbName: dbName.order,
		fieldName: "amount_info.payment_amount",
		whereJson: {
			user_id: uid,
			status: _.in([1, 2, 3, 4])
		}
	});
	// 数据库操作结束-----------------------------------------------------------
	return res;
};

/**
 * 修改 - 订单发货
 * 调用示例
await vk.daoCenter.orderDao.orderSend({
	_id, // 订单ID
	express_name, // 快递公司名称
	express_no, // 快递单号
	send_name, // 发货人名称
	send_mobile, // 发货人手机号
	goods_sku_list, // 发货信息数据 { _id, send_num } 若 goods_sku_list 不传，代表全部发货
	update_send_time, // 是否更新发货时间
	oper_uid, // 操作员id
	send_sms, // 是否发送短信
});
 */
dao.orderSend = async (obj) => {
	let { vk, _ } = util;
	let res = { code: 0, msg: '' };
	// 数据库操作开始-----------------------------------------------------------
	let {
		db, // 使用事务时需要
		_id, // 订单ID ，_id 和 orderInfo 只传1个即可
		orderInfo, // 订单信息，_id 和 orderInfo 只传1个即可
		mchInfo, // mchInfo 若传了mchInfo，则下面不再获取mchInfo
		express_name, // 快递公司名称
		express_no, // 快递单号
		send_name, // 发货人名称
		send_mobile, // 发货人手机号
		goods_sku_list, // 发货信息数据 { _id, send_num } 若 goods_sku_list 不传，代表全部发货
		update_send_time = true, // 是否更新发货时间
		oper_uid = "system", // 操作员id
		send_sms = false, // 是否发送短信
	} = obj;
	let time = Date.now(); // 当前时间
	let isAllSend = true; // 判断到只要有一个数据的发货数量小于可发货数量，那就标记为部分发货
	let send_time; // 发货时间
	let auto_confirm_receive_time; // 用户自动确认收货时间
	// 获取订单信息
	if (!orderInfo) orderInfo = await vk.daoCenter.orderDao.findById(_id);
	if (vk.pubfn.isNull(orderInfo)) return { code: -1, msg: '订单不存在' }
	if (orderInfo.status === -2) return { code: 0, msg: '该订单已申请退款，暂不能发货！', orderInfo }
	// 订单需要判断 enable_delivery = true 才能发货
	if (!orderInfo.enable_delivery) return { code: 0, msg: '该订单不符合发货条件', orderInfo }
	if (!orderInfo.send_time) { //如果发现数据没有对应的发货时间,强制让发货时间被勾选一下
		update_send_time = true;
	}
	if (update_send_time) {
		// 更新发货时间
		send_time = time;
		if (!mchInfo) mchInfo = await vk.daoCenter.mchDao.find();
		let day = vk.pubfn.getData(mchInfo, "order.auto_confirm_receive", 7);
		auto_confirm_receive_time = vk.pubfn.getOffsetTime(send_time, {
			day: day,
			mode: "after", // after 之后 before 之前
		});
	}
	if (goods_sku_list) {
		let ids = [];
		// 判断是否是全发完状态
		goods_sku_list.map((item, index) => {
			ids.push(item._id)
		});
		if (orderInfo.goods_sku_list.length !== goods_sku_list.length) {
			return { code: -1, message: '参数错误' }
		}
		// 因为前端传过来的 buy_num 并不可信任，故以数据库中为准（可信任）
		for (let i in orderInfo.goods_sku_list) {
			let item = vk.pubfn.getListItem(goods_sku_list, "_id", orderInfo.goods_sku_list[i]._id);
			// 设置发货数量
			orderInfo.goods_sku_list[i].send_num = item.send_num;
		}
		// 判断是否是全发完状态
		orderInfo.goods_sku_list.map((item, index) => {
			let {
				buy_num = 0,
					send_num = 0,
					refund_num = 0
			} = item;
			let max_send_num = buy_num - refund_num;
			if (max_send_num > item.send_num) {
				isAllSend = false; // 判断到只要有一个数据的发货数量小于可发货数量，那就标记为部分发货
			}
		});
	} else {
		// goods_sku_list 不传,代表全部发货
		for (let i in orderInfo.goods_sku_list) {
			// 设置发货数量 = 购买数量 - 退款数量
			let { buy_num = 0, refund_num = 0 } = orderInfo.goods_sku_list[i];
			let max_send_num = buy_num - refund_num;
			orderInfo.goods_sku_list[i].send_num = max_send_num;
		}
		isAllSend = true; // 设置为已全部发货
	}
	// 订单时间线
	let timeline = { time, msg: "商家发货", type: "send", oper_type: "business", oper_uid };
	// 修改订单信息，并返回最新的订单信息
	res.orderInfo = await vk.daoCenter.orderDao.updateAndReturn({
		db,
		whereJson: {
			_id: orderInfo._id
		},
		dataJson: {
			goods_sku_list: _.set(orderInfo.goods_sku_list), // 更新商品发货数据
			"express_info.express_name": express_name,
			"express_info.express_no": express_no,
			"express_info.send_name": send_name,
			"express_info.send_mobile": send_mobile,
			status: isAllSend ? 4 : 3, //修改订单状态 3 部分发货 4 已全部发货
			send_time,
			auto_confirm_receive_time,
			timeline: _.push(timeline)
		}
	});
	if (!res.orderInfo) return { code: -1, msg: "发货失败，请重试！" };
	if (send_sms) {
		// 发送短信提醒
		// res.sendSms = await vk.system.smsUtil.sendSms({
		// 	provider: "aliyun",
		// 	phone: orderInfo.express_info.receiver_mobile,
		// 	templateId: "SMS_215802305",
		// 	data: {
		// 		orderNo: orderInfo.order_no,
		// 		express_name,
		// 		express_no
		// 	}
		// });
	}

	// 数据库操作结束-----------------------------------------------------------
	return res;
};


/**
 * 查 - 获取用户商品的购买数量
 * 调用示例
let num = await vk.daoCenter.orderDao.getUserBuyNumByGoodsId({
	user_id,
	_add_time,
	status,
	goods_id,
});
 */
dao.getUserBuyNumByGoodsId = async (obj = {}) => {
	let { vk, db, _ } = util;
	let res = {};
	let {
		user_id,
		_add_time,
		status,
		goods_id,
	} = obj;
	// 数据库操作开始-----------------------------------------------------------
	let groupRes = await vk.baseDao.selects({
		dbName: dbName.order,
		pageIndex: 1,
		pageSize: 1,
		getMain: true,
		getOne: true,
		// 主表where条件
		whereJson: {
			user_id,
			_add_time,
			status
		},
		// 数组字段拆分成虚拟表
		unwindJson: {
			path: '$goods_sku_list', // 必填项，想要拆分的数组的字段名
			includeArrayIndex: "index", // 可选项，传入一个新的字段名，数组索引会保存在这个新的字段上。新的字段名不能以 $ 开头。
			preserveNullAndEmptyArrays: false, // 可选项，如果为 true，那么在 path 对应的字段为 null、空数组或者这个字段不存在时，依然会输出这个文档；如果为 false，unwind 将不会输出这些文档。默认为 false。
			replaceRoot: true, // 可选项，是否将 unwind 内的path字段作为后续的虚拟表，当为true时，includeArrayIndex参数将失效
			// 拆分后的where条件
			// unwindWhereJson: {
			// 	"goods_sku_list.goods_id": goods_id
			// },
			// replaceRoot后的where条件
			replaceRootWhereJson: {
				goods_id
			}
		},
		groupJson: {
			_id: "$goods_id", // _id是分组id， $ 后面接字段名，如user_id字段进行分组
			buy_num: _.$.sum("$buy_num"), // $ 后面接字段名，sum(1)代表求记录数量
			refund_num: _.$.sum("$refund_num"), // $ 后面接字段名，sum(1)代表求记录数量
		}
	});
	let { buy_num = 0, refund_num = 0 } = groupRes || {};
	// 数据库操作结束-----------------------------------------------------------
	return buy_num - refund_num;
};


/**
 * 计算，获取订单付款后可以获得的积分
 * 调用示例
let integral = await vk.daoCenter.orderDao.calcGiveIntegral({
	mchInfo,
	userInfo,
	goods_list,
	update: true, // 是否会更新goods_list内的give_integral
});
 */
dao.calcGiveIntegral = async (obj = {}) => {
	let { vk, db, _ } = util;
	let integralValue = 0;
	let {
		mchInfo,
		userInfo,
		goods_list,
		update, // 是否会更新goods_list内的give_integral
	} = obj;
	// 遍历商品列表
	goods_list.map((item, index) => {
		let {
			integral_rule = {},
				buy_num,
				should_payment_amount,
		} = item;
		let {
			is_calc = false,
				is_fixed_calc,
				proportion_value,
				fixed_value,
				is_level_k
		} = integral_rule;
		let giveIntegral = 0;
		if (is_calc) {
			let level_k = 1; // 等级倍率
			if (is_level_k) {
				let { vip_level_rule = [] } = mchInfo;
				let myVip = vk.pubfn.getListItem(vip_level_rule, "lv", userInfo.vip_lv);
				level_k = myVip.integral_ratio || 0;
			}
			if (is_fixed_calc) {
				// 固定
				giveIntegral = buy_num * fixed_value * level_k;
			} else {
				// 百分比
				giveIntegral = proportion_value * vk.pubfn.toDecimal(should_payment_amount / 100, 2) * level_k;
			}
			giveIntegral = Math.floor(giveIntegral); // 向下取整
			integralValue += giveIntegral;
		}
		if (update) {
			item.give_integral = giveIntegral; // 设置该商品奖励的积分数量
		}
	});
	integralValue = Math.floor(integralValue); // 向下取整
	//console.log('积分: ', integralValue)
	return integralValue;
};


/**
 * 计算，获取订单退款后需要扣除的积分
 * 调用示例
let integral = await vk.daoCenter.orderDao.calcRefundGiveIntegral({
	refund_goods_list,
	update: true, // 是否会更新goods_list内的refund_give_integral
});
 */
dao.calcRefundGiveIntegral = async (obj = {}) => {
	let { vk, db, _ } = util;
	let integralValue = 0;
	let {
		refund_goods_list,
		update, // 是否会更新goods_list内的refund_give_integral
	} = obj;
	refund_goods_list.map((item) => {
		let {
			refund_amount, // 退款金额
			payment_amount, // 付款金额
			buy_info, // 购买信息
		} = item;
		let {
			give_integral = 0, // 赠送积分数量
				refund_give_integral = 0, // 积分已退回数量（因退款而扣除的数量）
		} = buy_info;
		// 退款时向上取整，付款时向下取整（重要）
		let value = Math.ceil(refund_amount / payment_amount * give_integral);
		// 注意，如果多次部分退款，由于精度问题，可能会有0.01的偏差，为了解决偏差，最后一次退款需要特殊处理
		let maxValue = give_integral - refund_give_integral;
		if (value > maxValue) {
			value = maxValue;
		}
		if (update) {
			item.refund_give_integral = value;
		}
		integralValue += value;
	});
	return integralValue;
};


/**
 * 计算，获取订单退款后需要退回的积分
 * 调用示例
let integral = await vk.daoCenter.orderDao.calcRefundUsedIntegral({
	refund_goods_list,
	update: true, // 是否会更新goods_list内的refund_used_integral
});
 */
dao.calcRefundUsedIntegral = async (obj = {}) => {
	let { vk, db, _ } = util;
	let integralValue = 0;
	let {
		refund_goods_list,
		update, // 是否会更新goods_list内的refund_used_integral
	} = obj;
	refund_goods_list.map((item) => {
		let {
			refund_amount, // 退款金额
			payment_amount, // 付款金额
			refund_num, // 退款数量
			buy_num, // 购买数量
			buy_info, // 购买商品信息
		} = item;
		let {
			used_integral = 0, // 使用积分数量
				refund_used_integral = 0, // 以退回的使用积分数量
		} = buy_info;
		let value;

		if (payment_amount == 0) {
			// 如果订单实付金额为0时，value = 退款商品数量 / 购买商品数量 * 使用的积分
			// 退款时向上取整，付款时向下取整（重要）
			value = Math.ceil(refund_num / buy_num * used_integral);
		} else {
			// 如果订单实付金额>0时，value = 退款金额 / 付款金额 * 使用的积分
			// 退款时向上取整，付款时向下取整（重要）
			value = Math.ceil(refund_amount / payment_amount * used_integral);
		}

		// 注意，如果多次部分退款，由于精度问题，可能会有0.01的偏差，为了解决偏差，最后一次退款需要特殊处理（重要）
		let maxValue = used_integral - refund_used_integral;
		// 不可以超过该订单当前最大可退积分数量
		if (value > maxValue) {
			value = maxValue;
		}
		if (update) {
			item.refund_used_integral = value;
		}
		integralValue += value;
	});
	return integralValue;
};

module.exports = dao;
